// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#include <cantor/transform/expr.h>
#include <cantor/transform/exprs/constant_expr.h>
#include <cantor/transform/exprs/range_var.h>
#include <cantor/transform/exprs/row_expr.h>
#include <cantor/transform/dqls/subquery_expr.h>
#include <cantor/transform/dqls/exists_subquery_expr.h>
#include <cantor/transform/dqls/common_table_expr.h>
#include <cantor/transform/dqls/compare_subquery_expr.h>
#include <cantor/transform/functions/func_expr.h>
#include <cantor/transform/functions/ctor_map_func.h>
#include <cantor/transform/functions/ctor_struct_func_expr.h>
#include <cantor/transform/functions/ctor_union_func_expr.h>
#include <cantor/transform/functions/ctor_array_func_expr.h>
#include <cantor/transform/functions/ctor_set_func_expr.h>
#include <cantor/transform/functions/ctor_tuple_func_expr.h>
#include <cantor/transform/functions/ctor_json_func_expr.h>
#include <cantor/transform/functions/ctor_json_array_func_expr.h>
#include <cantor/transform/functions/ctor_proto_func_expr.h>
#include <cantor/transform/functions/ctor_enum_func_expr.h>
#include <cantor/transform/functions/ctor_udf_func_expr.h>
#include <cantor/transform/functions/when_clause_func.h>
#include <cantor/transform/functions/case_when_clause_func.h>

namespace cantor::transform {
    void TransExpr::resolve_constant_expr(const cantor::parser::DispatchExpr *node) {
        TransConstantExpr constant_expr;
        auto ptr = static_cast<const cantor::parser::ConstantExpr *>(node);
        constant_expr.resolve_ast(ptr);
        status = constant_expr.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_constant_expr() = std::move(constant_expr.const_expr);
        expr.set_type(pb::ast::ENT_CONSTANT_EXPR);
    }

    void TransExpr::resolve_range_var(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::RangeVar *>(node);
        status = TransRangeVar::resolve_to(ptr, expr.mutable_range_var());
        if (!status.ok()) {
            return;
        }
        expr.set_type(pb::ast::ENT_RANGE_VAR);
    }

    void TransExpr::resolve_row_expr(const cantor::parser::DispatchExpr *node) {
        TransRowExpr row_var;
        auto ptr = static_cast<const cantor::parser::RowExpr *>(node);
        row_var.resolve_ast(ptr);
        status = row_var.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_row_expr() = std::move(row_var.row_expr);
        expr.set_type(pb::ast::ENT_ROW_EXPR);
    }


    void TransExpr::resolve_subquery_expr(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::SubqueryExpr *>(node);
        TransSubqueryExpr subquery_expr;
        subquery_expr.resolve_ast(ptr);
        status = subquery_expr.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_subquery_expr() = std::move(subquery_expr.subquery_expr);
        expr.set_type(pb::ast::ENT_SUB_QUERY_EXPR);
    }

    void TransExpr::resolve_exists_subquery_expr(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::ExistsSubqueryExpr *>(node);
        TransExistsSubqueryExpr exists_subquery_expr;
        exists_subquery_expr.resolve_ast(ptr);
        status = exists_subquery_expr.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_exists_subquery_expr() = std::move(exists_subquery_expr.exists_subquery_expr);
        expr.set_type(pb::ast::ENT_EXISTS_SUB_QUERY_EXPR);
    }

    void TransExpr::resolve_common_subquery_expr(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CommonTableExpr *>(node);
        TransCommonTableExpr common_table_expr;
        common_table_expr.resolve_ast(ptr);
        status = common_table_expr.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_common_table_expr() = std::move(common_table_expr.common_table_expr);
        expr.set_type(pb::ast::ENT_COMMON_TABLE_EXPR);
    }


    void TransExpr::resolve_compare_subquery_expr(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CompareSubqueryExpr *>(node);
        TransCompareSubqueryExpr compare_subquery_expr;
        compare_subquery_expr.resolve_ast(ptr);
        status = compare_subquery_expr.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_compare_subquery_expr() = std::move(compare_subquery_expr.compare_subquery_expr);
        expr.set_type(pb::ast::ENT_COMPARE_SUBQUERY_EXPR);
    }

    void TransExpr::resolve_func_expr(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::FuncExpr *>(node);
        TransFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_func_expr() = std::move(trans.func_expr);
        expr.set_type(pb::ast::ENT_FUNC_EXPR);
    }

    void TransExpr::resolve_ctor_map_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorMapFuncExpr *>(node);
        TransCtorMapFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_map_func_expr() = std::move(trans.ctor_map_func_expr);
        expr.set_type(pb::ast::ENT_MAP_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_struct_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorStructFuncExpr *>(node);
        TransCtorStructFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_struct_func_expr() = std::move(trans.ctor_struct_func_expr);
        expr.set_type(pb::ast::ENT_STRUCT_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_union_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorUnionFuncExpr *>(node);
        TransCtorUnionFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_union_func_expr() = std::move(trans.ctor_union_func_expr);
        expr.set_type(pb::ast::ENT_UNION_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_array_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorArrayFuncExpr *>(node);
        TransCtorArrayFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_array_func_expr() = std::move(trans.ctor_array_func_expr);
        expr.set_type(pb::ast::ENT_ARRAY_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_set_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorSetFuncExpr *>(node);
        TransCtorSetFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_set_func_expr() = std::move(trans.ctor_set_func_expr);
        expr.set_type(pb::ast::ENT_SET_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_tuple_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorTupleFuncExpr *>(node);
        TransCtorTupleFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_tuple_func_expr() = std::move(trans.ctor_tuple_func_expr);
        expr.set_type(pb::ast::ENT_TUPLE_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_json_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorJsonFuncExpr *>(node);
        TransCtorJsonFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_json_func_expr() = std::move(trans.ctor_json_func_expr);
        expr.set_type(pb::ast::ENT_JSON_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_json_array_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorJsonArrayFuncExpr *>(node);
        TransCtorJsonArrayFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_json_array_func_expr() = std::move(trans.ctor_json_array_func_expr);
        expr.set_type(pb::ast::ENT_JSON_ARRAY_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_proto_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorProtoFuncExpr *>(node);
        TransCtorProtoFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_proto_func_expr() = std::move(trans.ctor_proto_func_expr);
        expr.set_type(pb::ast::ENT_PROTO_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_enum_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorEnumFuncExpr *>(node);
        TransCtorEnumFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_enum_func_expr() = std::move(trans.ctor_enum_func_expr);
        expr.set_type(pb::ast::ENT_ENUM_CTOR_FUNC);
    }

    void TransExpr::resolve_ctor_udf_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::CtorUdfFuncExpr *>(node);
        TransCtorUdfFuncExpr trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_ctor_udf_func_expr() = std::move(trans.ctor_udf_func_expr);
        expr.set_type(pb::ast::ENT_UDF_CTOR_FUNC);
    }

    void TransExpr::resolve_when_clause_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::FuncWhenClause *>(node);
        TransFuncWhenClause trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_func_when_clause() = std::move(trans.func_when_clause);
        expr.set_type(pb::ast::ENT_FUNC_WHEN_CLAUSE);
    }

    void TransExpr::resolve_case_when_clause_func(const cantor::parser::DispatchExpr *node) {
        auto ptr = static_cast<const cantor::parser::FuncCaseWhenClause *>(node);
        TransFuncCaseWhenClause trans;
        trans.resolve_ast(ptr);
        status = trans.check();
        if (!status.ok()) {
            return;
        }
        *expr.mutable_func_case_when_clause() = std::move(trans.func_case_when_clause);
        expr.set_type(pb::ast::ENT_FUNC_CASE_WHEN_CLAUSE);
    }

    void TransExpr::resolve_ast(const cantor::parser::DispatchExpr *node) {
        if (!node) {
            status = turbo::data_loss_error("node is nullptr");
            return;
        }
        switch (node->expr_type) {
            case cantor::pb::ast::ENT_CONSTANT_EXPR: {
                resolve_constant_expr(node);
                return;
            }
            case cantor::pb::ast::ENT_RANGE_VAR: {
                resolve_range_var(node);
                return;
            }
            case cantor::pb::ast::ENT_FUNC_EXPR:
                resolve_func_expr(node);
                return;
            case cantor::pb::ast::ENT_MAP_CTOR_FUNC:
                resolve_ctor_map_func(node);
                return;
            case cantor::pb::ast::ENT_STRUCT_CTOR_FUNC:
                resolve_ctor_struct_func(node);
            case cantor::pb::ast::ENT_UNION_CTOR_FUNC:
                resolve_ctor_union_func(node);
            case cantor::pb::ast::ENT_ARRAY_CTOR_FUNC:
                resolve_ctor_array_func(node);
            case cantor::pb::ast::ENT_SET_CTOR_FUNC:
                resolve_ctor_set_func(node);
                return;
            case cantor::pb::ast::ENT_TUPLE_CTOR_FUNC:
                resolve_ctor_tuple_func(node);
                return;
            case cantor::pb::ast::ENT_JSON_CTOR_FUNC:
                resolve_ctor_json_func(node);
                return;
            case cantor::pb::ast::ENT_JSON_ARRAY_CTOR_FUNC:
                resolve_ctor_json_array_func(node);
                return;
            case cantor::pb::ast::ENT_ENUM_CTOR_FUNC:
                resolve_ctor_enum_func(node);
                return;
            case cantor::pb::ast::ENT_PROTO_CTOR_FUNC:
                resolve_ctor_proto_func(node);
                return;
            case cantor::pb::ast::ENT_UDF_CTOR_FUNC:
                resolve_ctor_udf_func(node);
                return;
            case cantor::pb::ast::ENT_FUNC_WHEN_CLAUSE:
                resolve_when_clause_func(node);
                return;
            case cantor::pb::ast::ENT_FUNC_CASE_WHEN_CLAUSE:
                resolve_case_when_clause_func(node);
                return;
            case pb::ast::ENT_SUB_QUERY_EXPR:
                resolve_subquery_expr(node);
                return;
            case pb::ast::ENT_EXISTS_SUB_QUERY_EXPR:
                resolve_exists_subquery_expr(node);
                return;
            case pb::ast::ENT_COMMON_TABLE_EXPR:
                resolve_common_subquery_expr(node);
                return;
            case pb::ast::ENT_COMPARE_SUBQUERY_EXPR:
                resolve_subquery_expr(node);
                return;
            default:
                status = turbo::invalid_argument_error("Unknown expr type", static_cast<int>(node->expr_type));
        }
    }

    const turbo::Status &TransExpr::check() {
        if (!status.ok()) {
            return status;
        }
        return status;
    }

    turbo::Status TransExpr::resolve_to(turbo::Nonnull<const cantor::parser::DispatchExpr *> node,
                                        turbo::Nonnull<pb::ast::DispatchExpr *> proto_node) {
        TransExpr texpr;
        texpr.resolve_ast(node);
        auto status = texpr.check();
        if (!status.ok()) {
            return status;
        }
        *proto_node = std::move(texpr.expr);
        return status;
    }
} // namespace cantor::transform
